#include <clusnet/base/ObjectPool.h>
#include <gtest/gtest.h>
#include <clusnet/base/Timestamp.h>

#include <string>
#include <vector>

using namespace clusnet::base;

class SingleObj final
{
    public:
        SingleObj(const SingleObj&) = delete;
        SingleObj& operator= (const SingleObj&) = delete; 
        SingleObj()
            : str_("hello")
        {
            g_count++;
        }
        SingleObj(const std::string& str)
            : str_(str)
        {
            g_count++;
        }
        ~SingleObj()
        {
            g_count--;
        }

        std::string context()
        {
            return str_;
        }

    public:
        static size_t g_count;

    private:
        std::string str_;
};

size_t SingleObj::g_count = 0;

TEST(ObjectPool, Test_object)
{
    ObjectPool<SingleObj>    pool;
    {
        auto obj1 = pool.acquire();
        ASSERT_EQ(obj1->context(), "hello");
        auto obj2 = pool.acquire("world");
        ASSERT_EQ(obj2->context(), "world");
        ASSERT_EQ(SingleObj::g_count, 2);
    }
    ASSERT_EQ(SingleObj::g_count, 0);
    ASSERT_FALSE(pool.checkLeak());
}

void testBench(size_t count)
{
    Timestamp start(Timestamp::now());
    Timestamp acquire(Timestamp::invalid());
    ObjectPool<SingleObj> pool;
    {
        std::vector<std::shared_ptr<SingleObj>> vec;
        for (size_t i = 0; i < count; ++i)
        {
            vec.push_back(pool.acquire());
        }
        acquire = Timestamp::now();
        std::cout << "process acquire " << count << " counts, spend " << timeDifference(acquire, start) * 1000000 << " us" << std::endl;
    }
    Timestamp release(Timestamp::now());
    std::cout << "process release " << count << " counts, spend " << timeDifference(release, acquire) * 1000000 << " us" << std::endl;
    ASSERT_FALSE(pool.checkLeak());
}

int main(int argc, char* argv[])
{
    testBench(1000000);
    testing::InitGoogleTest(&argc, argv);
    return RUN_ALL_TESTS();
}
